给 KV Cache 瘦身:MQA · GQA · MLA
原视频:给 KV Cache 瘦身:MQA · GQA · MLA
UP 主:古希腊掌管代码的神 | 时长:4:12 | tag:从 Transformer 到大模型现代架构(系列 19/20)
链接:https://www.bilibili.com/video/BV1H6JQ6iE8R
一句话结论
KV cache 的大小由 KV 头的数量决定:MHA 每个 Q 头配一组 KV;MQA 把所有 Q 头并成 1 组(缓存 ÷32,快但质量打折);GQA 分组共享(主流,质量近 MHA、速度近 MQA);MLA 干脆不缓存 K/V 本身,只缓存一个低秩潜向量,用时再展开(缓存再砍九成)。四者是同一条"质量 ↔ 显存"光谱上的选型,不是公式之争——MQA/GQA 改的只是 KV 头数与共享方式,注意力公式一字未动。
面试答法
30 秒版:先算账:KV cache 每 token 的大小 = 2(K 和 V)× 层数 × KV 头数 × head_dim × 数据字节数。以 7B、32 层、32 头、head_dim 128、FP16 为例,每 token 约 512 KB,4096 上下文就是约 2.1 GB,而且随长度和并发线性涨,解码又是访存瓶颈,所以推理端先顶不住的往往是 KV cache 而不是权重。瘦身三代:MQA(2019,Shazeer)让所有 Q 头共享 1 组 KV,缓存砍到 1/32,解码读的数据少了所以快,但质量会退化;GQA(2023)分组共享——如 32 个 Q 头分 8 组、每组共享 1 组 KV,缓存砍 3/4(头更多的 70B 是砍 7/8),论文结论是质量接近 MHA、速度接近 MQA,Llama 2 70B、Llama 3 都用 8 个 KV 头,还能用约 5% 预训练算力把老 MHA 模型 uptraining 改造成 GQA;MLA(DeepSeek-V2,2024)换思路:把 K/V 联合低秩投影成一个潜向量只缓存它,官方口径 KV cache 减少 93.3%、最大生成吞吐提升 5.76 倍。选型:追吞吐/长上下文用 GQA 或 MLA,显存够且追极致质量,MHA 依然成立。
核心原理
1. 先算账:显存花在哪
MHA 里每个 Q 头都有一组专属的 K 头和 V 头。32 头就是 32 组 KV 缓存:每生成一个 token,32 组都要写一遍;解码每一步又要把历史 KV 全部读回来。解码是 memory-bound——瓶颈是"搬多少",不是"算多少",这是后面所有优化的出发点。

2. 三代方案
- MQA(Multi-Query Attention):32 组并 1 组,所有 Q 头共用同一组 K/V。缓存 ÷32,解码搬运量骤降,所以快——快在搬得少,不在算得少。代价是表达能力:32 个"读者"共用一份索引,互相干扰,GQA 论文明确指出其质量退化与训练不稳定问题。
- GQA(Grouped-Query Attention):把共享做成小组。32 个 Q 头分 8 组、每组 4 个 Q 头共享 1 组 KV,每 token 缓存从约 512 KB 降到约 128 KB。压缩比取决于头数口径:32 头配 8 组是 ÷4;Llama 2 70B 是 64 个 Q 头配 8 组,是 ÷8。配套的 uptraining:把 MHA checkpoint 的 KV 头做均值池化得到初始 GQA 权重,再用约原预训练 5% 的算力续训即可改造完成。
- MLA(Multi-head Latent Attention):不再缓存 K/V 本身,而是把它们联合投影、压缩成一个低维潜向量(latent)存下来,需要时再向上投影还原各头的 K/V。DeepSeek-V3 的配置下,每 token 每层只存 576 个数 = 512 维潜向量 $c_{kv}$ + 64 维解耦 RoPE 分量,61 层合计约 70 KB/token,比同规格 MHA 少一个数量级。


3. 一条光谱
MHA(质量满分、显存最贵)→ GQA(砍 3/4 起、质量几乎不伤)→ MQA(砍到 1/32、质量打折)→ MLA(砍九成以上、质量与 MHA 持平)。显存越省,能开的批量并发越大、上下文越长。旗舰模型全部"瘦身",本质都是在用这条光谱换推理经济性。
易错点与常见追问
- 数字口径要对齐:GQA 的压缩比 = Q 头数 ÷ KV 头数,先报模型的头数再说砍多少,别把"÷4"当成 GQA 的固定值(70B 是 ÷8,Llama 3 8B 是 32÷8=÷4)。
- 为什么 MQA 快:不是计算量变小(Q·K 的乘法还要广播做),而是解码时从 HBM 读回的 KV 数据少了 32 倍——能答出 memory-bound 这一点,才算讲透。
- MLA 的 64 维 RoPE 分量是全头共享的一把"钥匙":MLA 把位置信息从潜向量里解耦出来,单独存一个共享的 RoPE key;若直接对潜向量做 RoPE,位置会和内容纠缠、无法预计算,这是 DeepSeek 设计里最精巧的一步,高频追问。
- MLA 推理时不真的"展开再算":实现上可以把向上投影矩阵吸收(absorb)进 Q 投影和输出投影,直接在潜向量空间做注意力,避免把各头 K/V 显式还原出来;否则省显存不省带宽,收益会打折。
- KV cache 还随 batch 线性涨:视频强调的是长度维度;面试算总账时要再乘并发 batch,并和权重、激活一起对显存预算。
- 和 KV 量化/淘汰是正交的:头数瘦身之外,还有 KV 量化(INT8/INT4)、H2O/SnapKV 这类 token 淘汰、PagedAttention 的显存管理——被追问"还能怎么省"时按这条线展开。
修订说明
- 视频的结论与关键数字(MQA ÷32、GQA 分组与 uptraining 约 5%、MLA -93.3% 与吞吐 ×5.76、V3 每层 576 个数)与原论文/官方口径一致,无硬错误。以下为口径层面的收紧,已在正文处理:
- 每 token "512,000 字节 / 128,000 字节"是约数;精确值是 524,288 B(512 KiB)与 131,072 B,2.1 GB 的总账也是按 batch=1、4096 上下文算的——答题时应声明 batch 与长度口径,视频未点明 batch 维度。
- MLA 部分视频只讲"压缩—展开",未提投影吸收(absorption)这一实现关键;不吸收的话带宽收益会缩水,已在追问里补上。
- "-93.3%、×5.76"出自 DeepSeek-V2 官方(相对其 MHA 基线的口径),不同模型/框架实测会变,引用时应带出处而非当作普遍常数。
- 配图均为视频截图(1:02 / 1:40 / 3:06)。